{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T09:43:54.725767Z",
     "start_time": "2020-08-26T09:43:54.719155Z"
    }
   },
   "source": [
    "# [python函数参数中的`*`、`*args`、`**`和`**kwargs`](https://www.cnblogs.com/bawu/p/8243108.html)\n",
    "让我们通过以下6步来理解：\n",
    "\n",
    "1. 通过一个函数调用来理解`*`的作用\n",
    "2. 通过一个函数的定义来理解`*args`的含义\n",
    "3. 通过一个函数的调用来理解`**`的作用\n",
    "4. 通过一个函数的定义来理解`**kwargs`的含义\n",
    "5. 注意点：参数`arg`、`*args`、`**kwargs`三个参数的位置必须是一定的。必须是`(arg,*args,**kwargs)`这个顺序，否则程序会报错。\n",
    "6. 通过一个应用实例来说明`args`,`kwargs`应用场景以及为何要使用它"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `*`的作用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T09:48:41.075915Z",
     "start_time": "2020-08-26T09:48:41.067575Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 3\n",
      "1 2 3\n",
      "1 2 3\n"
     ]
    }
   ],
   "source": [
    "def fun(a,b,c):\n",
    "    print(a,b,c)\n",
    "\n",
    "fun(1,2,3)  #1 2 3\n",
    "\n",
    "l=[1,2,3]\n",
    "fun(*l)   #1 2 3\n",
    "\n",
    "l=(1,2,3)\n",
    "fun(*l)  #1 2 3  元组也可以\n",
    "\n",
    "#l=[1,2,3,4]\n",
    "#fun(*l)  #TypeError: fun() takes 3 positional arguments but 4 were given"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`*`做了什么？\n",
    "\n",
    "**它拆开数列`l`的数值作为位置参数，并吧这些位置参数传给函数`fun`来调用**。\n",
    "\n",
    "因此拆数列、传位置参数意味着`fun(*l)`与`fun(1,2,3)`是等效的，因为l = [1,2,3]\n",
    "\n",
    "数列`l`含有四个数值.因此，我们试图调用`fun(*l)`，`l`中数值拆开传给函数fun作为位置参数。\n",
    "\n",
    "但是，`l`中有四个数值，调用`fun(*l)`相当于调用`fun(3,6,9,1)`,又因为函数`fun`定义中只用三个位置参数，因此我们得到这个错误。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `*args`的含义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T09:51:57.373911Z",
     "start_time": "2020-08-26T09:51:57.367139Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(10,) <class 'tuple'>\n",
      "(10, 20) <class 'tuple'>\n",
      "([1, 2], 20, [2, 3]) <class 'tuple'>\n"
     ]
    }
   ],
   "source": [
    "def fun(*args):\n",
    "    print(args,type(args))\n",
    "\n",
    "fun(10)     #(10,) <class 'tuple'>\n",
    "fun(10,20)  #(10,20) <class 'tuple'>\n",
    "fun([1,2],20,[2,3])  #([1, 2],) <class 'tuple'>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T09:52:04.843966Z",
     "start_time": "2020-08-26T09:52:04.836775Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 (3, 4, 5)\n"
     ]
    }
   ],
   "source": [
    "#代码2\n",
    "def fun(x,y,*args):\n",
    "    print(x,y,args)\n",
    "\n",
    "fun(1,2,3,4,5) #1 2 (3, 4, 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T09:52:07.200320Z",
     "start_time": "2020-08-26T09:52:07.189012Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "fun() missing 1 required keyword-only argument: 'z'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-25-3e4095265543>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      3\u001b[0m     \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mz\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mfun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m#TypeError: fun() missing 1 required keyword-only argument: 'z'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: fun() missing 1 required keyword-only argument: 'z'"
     ]
    }
   ],
   "source": [
    "#代码3\n",
    "def fun(x,y,*args,z):\n",
    "    print(x,y,args,z)\n",
    "\n",
    "fun(1,2,3,4,5) #TypeError: fun() missing 1 required keyword-only argument: 'z'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可见：\n",
    "1. `*args` 用来将参数打包成tuple给函数体调用，参数个数不受限制，`*args`接收元组作为位置参数\n",
    "2. 由代码2知：x为1，y为2，即第一个和第二个位置参数，之后只有一个参数`*args`，因此，`*args`接收除第一个和第二个参数之外的参数作为元组，即(3,4,5)。\n",
    "3. 由代码3知：位置参数z不能放置在`*args`之后"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `**`的作用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T09:56:58.405094Z",
     "start_time": "2020-08-26T09:56:58.389138Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 3\n",
      "1 2 3\n",
      "1 2 3\n",
      "1 2 3\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "fun() got an unexpected keyword argument 'd'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-26-d36adcb571ec>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     12\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     13\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'a'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'b'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'c'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'd'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 14\u001b[0;31m \u001b[0mfun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m    \u001b[0;31m#TypeError: fun() got an unexpected keyword argument 'd'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     15\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     16\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'a'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'b'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'd'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: fun() got an unexpected keyword argument 'd'"
     ]
    }
   ],
   "source": [
    "def fun(a,b,c):\n",
    "    print(a,b,c)\n",
    "\n",
    "fun(1,2,3)       #1 2 3\n",
    "fun(a=1,b=2,c=3) #1 2 3\n",
    "\n",
    "d={'b':2,'c':3}\n",
    "fun(1,**d)       #1 2 3\n",
    "\n",
    "dict={'b':2,'c':3}\n",
    "fun(1,**dict)       #1 2 3\n",
    "\n",
    "d={'a':1,'b':2,'c':3,'d':4}\n",
    "fun(**d)    #TypeError: fun() got an unexpected keyword argument 'd'\n",
    "\n",
    "d={'a':1,'b':2,'d':4}\n",
    "fun(**d)    #TypeError: fun() got an unexpected keyword argument 'd'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在函数调用中使用`*`，我们需要元组;在函数调用中使用`**`，我们需要一个字典，字典中参数个数不能多，也不能少。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `**kwargs`的含义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T10:05:23.508854Z",
     "start_time": "2020-08-26T10:05:23.495535Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 {'b': 2, 'c': 3}\n",
      "1 {'b': 2, 'c': 3}\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "fun() takes 1 positional argument but 2 were given",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-29-c669810dceda>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0mfun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'b'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'c'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m   \u001b[0;31m#1 {'b': 2, 'c': 3}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0mfun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'b'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'c'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m     \u001b[0;31m#TypeError: fun() takes 1 positional argument but 2 were given\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: fun() takes 1 positional argument but 2 were given"
     ]
    }
   ],
   "source": [
    "def fun(a,**kwargs):\n",
    "    print(a,kwargs)\n",
    "\n",
    "fun(1,b=2,c=3)           #1 {'b': 2, 'c': 3}\n",
    "\n",
    "fun(1,**{'b':2,'c':3})   #1 {'b': 2, 'c': 3}\n",
    "\n",
    "fun(1,{'b':2,'c':3})     #TypeError: fun() takes 1 positional argument but 2 were given"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在函数定义中`**kwargs`意味着什么？\n",
    "\n",
    "用`**kwargs`定义函数,kwargs接收除常规参数列表之外的键值参数字典，参数个数不固定，`kwargs`是个字典。\n",
    "\n",
    "可以多传参数吗？因为参数不固定，所以也就没有多少的概念了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 注意点：\n",
    "参数`arg`、`*args`、`**kwargs`三个参数的位置必须是一定的。必须是`(arg,*args,**kwargs)`这个顺序，否则程序会报错。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `args`，`kwargs`应用场景以及为何要使用它"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T10:10:39.771719Z",
     "start_time": "2020-08-26T10:10:39.750447Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "updated an existing record\n",
      "created a new record\n"
     ]
    },
    {
     "ename": "ValueError",
     "evalue": "cannt perform both operations",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-30-33cf93527a33>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     21\u001b[0m \u001b[0mchild\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msave\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mforce_update\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     22\u001b[0m \u001b[0mchild\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msave\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mforce_insert\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 23\u001b[0;31m \u001b[0mchild\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msave\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mforce_insert\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mforce_update\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     24\u001b[0m \u001b[0;31m# updated an existing record\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     25\u001b[0m \u001b[0;31m# created a new record\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m<ipython-input-30-33cf93527a33>\u001b[0m in \u001b[0;36msave\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m     13\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0msave\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     14\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m==\u001b[0m\u001b[0;34m'abcd'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m             \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msave\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     16\u001b[0m             \u001b[0;31m#super(Model,self).save(*args,**kwargs)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     17\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m<ipython-input-30-33cf93527a33>\u001b[0m in \u001b[0;36msave\u001b[0;34m(self, force_update, force_insert)\u001b[0m\n\u001b[1;32m      4\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0msave\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mforce_update\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mforce_insert\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mforce_update\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mforce_insert\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'cannt perform both operations'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m#故意写作cannt而非cannot\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      7\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mforce_update\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m             \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'updated an existing record'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: cannt perform both operations"
     ]
    }
   ],
   "source": [
    "class Model:\n",
    "    def __init__(self,name):\n",
    "        self.name=name\n",
    "    def save(self,force_update=False,force_insert=False):\n",
    "        if force_update and force_insert:\n",
    "            raise ValueError('cannt perform both operations') #故意写作cannt而非cannot\n",
    "        if force_update:\n",
    "            print('updated an existing record')\n",
    "        if force_insert:\n",
    "            print('created a new record')\n",
    "\n",
    "class Child(Model):\n",
    "    def save(self,*args,**kwargs):\n",
    "        if self.name=='abcd':\n",
    "            super().save(*args,**kwargs)\n",
    "            #super(Model,self).save(*args,**kwargs)\n",
    "        else:\n",
    "            return None\n",
    "\n",
    "child=Child('abcd')\n",
    "child.save(force_update=True)\n",
    "child.save(force_insert=True)\n",
    "child.save(force_insert=True,force_update=True)\n",
    "# updated an existing record\n",
    "# created a new record\n",
    "# ValueError: cannt perform both operations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "实际上对应的保存动作发生在`Model`的`save`方法中。所以我们调用子类的的`save()`方法而非`Mode`的方法.子类`Child`的`save()`接收任何父类`save()`需要的参数，并传给父类方法。因此,子类`save()`方法参数列表中有`*args`和`**kwargs`,它们可以接收任意位置参数或键值参数,常规参数列表除外。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
